package util.bitmap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;

import javax.net.ssl.HttpsURLConnection;
/**
 * @author Hunter
 * @param <T>
 * 要处理解码图片过程中产生的OOM错误，需要调用registMemoryAlarm(MemoryListener listener);
 * 使用Img类之前需要先初始化FileUtil类
 * 需要文件读写权限和网络权限（不下载图片可以不要）
 */
public class Img<T>{
	private static Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
	private static PorterDuffXfermode duffXfermode;
	private String TAG = Img.class.getName();
	private int radius;
	public static final short SIZE_MODE_BASE_ON_WIDTH = 1;
	public static final short SIZE_MODE_BASE_ON_HEIGHT = 2;
	public static final short SIZE_MODE_BASE_ON_EXACTLY_ARGS = 3;
	public static final short SIZE_MODE_BASE_ON_ORIGIN_SIZE = 4;
	private short sizeMode = SIZE_MODE_BASE_ON_ORIGIN_SIZE;
	
	private boolean isSizeKnown;
	private File cacheDirectory;
	/**
	 * 与之绑定的ImageView
	 */
	private HashSet<View> viewSet;
	
	/**
	 * 加载到内存中的Bitmap
	 */
	private Bitmap bitmap;
	
	/**
	 * 生成的缩略图的文件路径
	 */
	private String cacheFilePath = "";
	
	private T data;
	
	/**
	 * 解码出来的Bitmap的高度（单位像素）
	 */
	private int height;
	/**
	 * 图片本地的文件路径
	 */
	private String filePath;
	/**
	 * 图片的url请求地址
	 */
	private String url;
	
	/**
	 * 解码出来的Bitmap的宽度（单位像素）
	 */
	private int width;
	
	
	public Img(File cacheDirectory, File fileDirecotry, String url){
		this(cacheDirectory, fileDirecotry.getPath()+'/'+(url==null?"null":url.hashCode())+".jpg");
		this.url = null==url?"":url;
	}
	
	public Img(File cacheDirectory, String filePath){
		this.filePath = filePath;
		this.cacheDirectory = cacheDirectory;
		this.viewSet = new HashSet<View>();
	}

	/**
	 * 删除图片缓存
	 */
	final public void deleteCacheFile(){
		new File(cacheFilePath).delete();
	}
	
	/**
	 * 删除图片源文件及缓存
	 */
	final public void deleteFile(){
		new File(filePath).delete();
		deleteCacheFile();
	}
	
	public void decodeBitmapAsync(final Handler h){
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					if(decodeBitmap()){
						h.sendEmptyMessage(0);
					}else{
						h.sendEmptyMessage(1);
					}
				} catch (Exception e) {
					h.sendEmptyMessage(1);
				}
				
			}
		}).start();
	}
	
	public boolean decodeBitmap() throws IOException{
		if(isBitmapDecoded()){
			return true;
		}
		getBitmapFromCache();
		if(null==bitmap){
			if(fileExists()){
				if(isSizeKnown || sizeMode==SIZE_MODE_BASE_ON_EXACTLY_ARGS){
					bitmap = ImgUtil.getBitmap(filePath, width, height);
				}else if(sizeMode==SIZE_MODE_BASE_ON_ORIGIN_SIZE){
					bitmap = ImgUtil.getBitmap(filePath);
				}else if(sizeMode==SIZE_MODE_BASE_ON_HEIGHT){
					bitmap = ImgUtil.getScaledBitmap(filePath, height);
				}else if(sizeMode==SIZE_MODE_BASE_ON_WIDTH){
					bitmap = ImgUtil.getScaledBitmap(width, filePath);
				}
				if(null!=bitmap){
					if(radius!=0){
						bitmap = ImgUtil.getCircleBitmap(bitmap);
					}
					if(sizeMode!=SIZE_MODE_BASE_ON_ORIGIN_SIZE){
						isSizeKnown = true;
					}
					width = bitmap.getWidth();
					height = bitmap.getHeight();
					saveCacheIfNecessary();
				}
			}
			
		}
		return null!=bitmap;
		
	}

	/**
	 * @param handler 0 下载成功， 1 URL格式不正确， 2 IO异常 
	 */
	public void downloadAsync(final Handler handler){
		new Thread(new Runnable() {
			public void run() {
				try {
					URL u = new URL(url);
					HttpsURLConnection connection = (HttpsURLConnection) u.openConnection();
					FileOutputStream fos = new FileOutputStream(filePath);
					InputStream is = connection.getInputStream();
					byte[] buffer = new byte[2048];
					int n = 0;
					do{
						fos.write(buffer, 0, n);
						n = is.read(buffer);
					}while(n!=-1);
					fos.close();
					handler.sendEmptyMessage(0);
				} catch (MalformedURLException e) {
					handler.sendEmptyMessage(1);
					e.printStackTrace();
				} catch (IOException e) {
					handler.sendEmptyMessage(2);
					e.printStackTrace();
				}
			}
		}).start();
	}
	
	public void downloadAndDecodeAsync(final Handler handler){
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
                    if(new File(filePath).exists() || download()){
                        if(decodeBitmap()){
                            handler.sendEmptyMessage(0);
                        }else{
                            handler.sendEmptyMessage(1);
                        }
                    }else{
                        handler.sendEmptyMessage(1);
                    }
				} catch (IOException e) {
					e.printStackTrace();
					handler.sendEmptyMessage(1);
				}
			}
		}).start();
	}

	public boolean download(){
        String suffix = ".tmp";
		boolean isDownloaded = false;
		FileOutputStream fos = null;
		try {
			URL u = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) u.openConnection();
			connection.setReadTimeout(3000);
			connection.setDoInput(true);
			connection.setDoOutput(false);
			connection.setConnectTimeout(10000);
			InputStream is = connection.getInputStream();
            File tmpFile = new File(filePath+suffix);
			fos = new FileOutputStream(tmpFile);
			byte[] buffer = new byte[2048];
			int n = 0;
			do{
				Thread.yield();
				fos.write(buffer, 0, n);
				n = is.read(buffer);
			}while(n!=-1);
			fos.close();
            tmpFile.renameTo(new File(filePath));
			isDownloaded = true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			if(!isDownloaded){
				new File(filePath+suffix).delete();
				Log.e(TAG, "Pic Download Failed ：URL = "+url);
			}
		}
		return isDownloaded;
		
	}
	
	/**
	 * 如果只设置宽或高，则返回等比例缩放的图片。如果都没设置则返回1:1的原图，如果都设置了则进行剪切缩放（如果长宽比例�?��则只进行缩放�?
	 */
	final public Bitmap getBitmap(){
		return bitmap;
	}
	
	/**
	 * @return 从缩略图中解码出Bitmap，如果不存在返回null
	 * @throws IOException 
	 */
	final private Bitmap getBitmapFromCache(){
		Bitmap bitmap = null;
		try {
			if(new File(cacheFilePath).exists()){
				bitmap =  ImgUtil.getBitmap(cacheFilePath);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bitmap;
		
	}
	
	/**
	 * 获取绑定的数据
	 * @return T
	 */
	public T getData(){
		return  data;
	}
	
	/**
	 * @return 在Bitmap加载之前可能为0
	 */
	public int getHeight(){
		return height;
	}
	
	public String getImagePath(){
		return this.filePath;
	}
	
	public String getUrl(){
		return url;
	}
	/**
	 * @return 在Bitmap加载之前可能为0
	 */
	public int getWidth(){
		return width;
	}
	
	public boolean isBitmapDecoded(){
		return null!=bitmap && !bitmap.isRecycled();
	}
	
	public void recycle(){
		if(null!=bitmap){
			if(!bitmap.isRecycled()){
				bitmap.recycle();
			}
			bitmap = null;
		}
	}
	
	final private void saveCacheIfNecessary(){
		if(null==bitmap){
			return;
		}
		//原始尺寸的图片
		if(sizeMode==SIZE_MODE_BASE_ON_ORIGIN_SIZE){
			return;
		}
		//缓存已经存在
		File file = new File(cacheFilePath);
		if(file.exists()){
			return;
		}
		//原始图片和目标Bitmap尺寸差距不大，没有缓存的意义
		BitmapFactory.Options options = ImgUtil.getSizeOptions(filePath);
		if(options.outHeight*options.outHeight<9*bitmap.getWidth()*bitmap.getHeight()){
			return;
		}
		ImgUtil.save(bitmap, cacheFilePath);
		
	}
	/**
	 * 缩略图的命名策略：源文件路径的哈希码
	 */
	final private void generateCachePath(){
		switch(sizeMode){
		case SIZE_MODE_BASE_ON_EXACTLY_ARGS:
			this.cacheFilePath = cacheDirectory.getPath()+"/"+filePath.hashCode()+'-'+width+'x'+height+".jpg";
			break;
		case SIZE_MODE_BASE_ON_HEIGHT:
			this.cacheFilePath = cacheDirectory.getPath()+"/"+filePath.hashCode()+'-'+sizeMode+'-'+height+".jpg";
			break;
		case SIZE_MODE_BASE_ON_WIDTH:
			this.cacheFilePath = cacheDirectory.getPath()+"/"+filePath.hashCode()+'-'+sizeMode+'-'+width+".jpg";
			break;
		default:
			this.cacheFilePath = filePath;
			break;
		}
		
	}
	
	/**
	 * 绑定数据
	 * @param obj
	 */
	public void setData(T obj){
		this.data = obj;
	}
	
	
	/**
	 * @param srcPath 图片的绝对路径
	 */
	public void setSrc(String srcPath){
		this.filePath = srcPath;
		isSizeKnown = false;
	}
	
	public void setUrl(String url){
		this.url = url;
		isSizeKnown = false;
	}
	
	public void setSizeBaseOnWidth(int width){
		this.width = width;
		sizeMode = SIZE_MODE_BASE_ON_WIDTH;
		generateCachePath();
	}
	public void setSizeBaseOnHeight(int height){
		this.height = height;
		sizeMode = SIZE_MODE_BASE_ON_HEIGHT;
		generateCachePath();
	}
	
	
	public void setSize(int size){
		setSize(size, size);
	}
	/**
	 * 调用此方法，则不能调用其他setSize()方法，生成的Bitmap将会是圆形的
	 * @param radius
	 */
	public void setRadius(int radius){
		this.radius = radius;
		setSize(radius*2, radius*2);
	}
	
	public void setSize(int width, int height){
		this.width = width;
		this.height = height;
		sizeMode = SIZE_MODE_BASE_ON_EXACTLY_ARGS;
		generateCachePath();
	}

	final public boolean fileExists(){
		return new File(filePath).exists();
	}

	final public HashSet<View> getBindedViews() {
		return viewSet;
	}
	
	final public void bindView(View view) {
		viewSet.add(view);
	}
	final public void unbindView(View view){
		viewSet.remove(view);
	}
	final public void setImageViewAsync(View imageView){
		final ImageView iv = (ImageView) imageView;
		if(isBitmapDecoded()){
			iv.setImageBitmap(bitmap);
		}else if(fileExists()){
			decodeBitmapAsync(new Handler(){
				@Override
				public void handleMessage(Message msg) {
					if(msg.what==0){
						iv.setImageBitmap(bitmap);
					}
				}
			});
		}else{
			downloadAndDecodeAsync(new Handler(){
				@Override
				public void handleMessage(Message msg) {
					if(msg.what==0){
						iv.setImageBitmap(bitmap);
					}
				}
			});
		}
	}
	
}